#include <stdio.h>
#include <stdint.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>

#include "syscore.h"
#include "apis.h"
#include "common.h"
#include "pactrl.h"
#include "modules.h"

#define KEEP_PA_ON_FOR_TEST  1

typedef struct tagPaAlarm {
    int32_t pa_addr;
    int32_t id;
    int32_t reason;
    int32_t action;
} PA_ALARM;

bool stop_process = false;
uint32_t is_gsm_ready = PARA_VALUE_GSM_WILELESS_OFF;
uint32_t is_pa_on = true;

uint8_t pa_up_att[2] = {0};
uint8_t pa_dn_att[2] = {0};
uint8_t pa_temp_threshold[2] = {0};
uint8_t pa_power_threshold[2] = {0};

int8_t paSwWarn[PA_NUM] = {0};
int8_t paTempWarn[PA_NUM] = {0};
int8_t is_pa_overtemp[PA_NUM] = {0};

MODREG modPaInfo = {MODULE_PA, false, false, 100,NULL};

void reportPaHeartBeat()
{
    U32 rc = PARA_VALUE_SYSMONITOR_MODULE_OK;
    CM_SendMsg_1Para(MODULE_SYSMONITOR, MODULE_PA, MSG_TYPE_COMMAND, CMD_EVENT, CMD_CODE_SYSMONITOR_HEARTBEAT, 0,
        PARA_TYPE_SYSMONITOR_MODULE_STATE,sizeof(U32), (U8*)&rc);   
}

void reportCmdResult(uint16_t dst_id, uint16_t cmd_code, uint16_t cmd_idx, uint32_t result, uint32_t err_code, uint8_t paAddr)
{
	char msg_buf[MSG_BUFF_SIZE] = {0};
    MSGHEADER *msg_header = (MSGHEADER *)msg_buf;
    void* msg_payload = (void*)(msg_buf + sizeof(MSGHEADER));

    msg_header->srcID = MODULE_PA;
    msg_header->dstID = dst_id;
    msg_header->mType = get_mtype(msg_header->dstID);
    msg_header->msgType = MSG_TYPE_COMMAND;

    PCMDHEADER cmd = (PCMDHEADER)msg_payload;
    cmd->cmdType = CMD_SET_RESPONSE;
    cmd->cmdCode = cmd_code;
    cmd->cmdIndex = cmd_idx;
    cmd->cmdLength = 0;

    msg_header->msgLength = sizeof(CMDHEADER) +sizeof(MSGHEADER);
    uint8_t *ptr = (uint8_t *)msg_payload;
    ptr += sizeof(CMDHEADER);

    if( PARA_VALUE_RESULT_FAILED == result )
    {
        *(uint32_t*)ptr = PARA_TYPE_RESULT;
        ptr += sizeof(uint32_t);
        *(uint32_t*)ptr = sizeof(uint32_t);
        ptr += sizeof(uint32_t);
        *(uint32_t*)ptr = PARA_VALUE_RESULT_FAILED;
        ptr += sizeof(uint32_t) + sizeof(uint32_t);
        cmd->cmdLength += sizeof(uint32_t) * 4;

        *(uint32_t*)ptr = PARA_TYPE_ERROR_CODE;
        ptr += sizeof(uint32_t);
        *(uint32_t*)ptr = sizeof(uint32_t);
        ptr += sizeof(uint32_t);
        *(uint32_t*)ptr = PARA_VALUE_ERROR_PA_OK + err_code;
        cmd->cmdLength += sizeof(uint32_t) * 3;
    }
    else
    {
        *(uint32_t*)ptr = PARA_TYPE_RESULT;
        ptr += sizeof(uint32_t);
        *(uint32_t*)ptr = sizeof(uint32_t);
        ptr += sizeof(uint32_t);
        *(uint32_t*)ptr = result;
        ptr += sizeof(uint32_t) + sizeof(uint32_t);
        cmd->cmdLength += sizeof(uint32_t) * 4;

        *(uint32_t *)ptr = PARA_TYPE_PA_ADDR;
        ptr += sizeof(uint32_t);
        *(uint32_t *)ptr = sizeof(uint8_t);
        ptr += sizeof(uint32_t);
        *(uint8_t *)ptr = paAddr;
        cmd->cmdLength += sizeof(uint32_t) * 4;
    }

    msg_header->msgLength += cmd->cmdLength;
    if( RC_OK != CM_sendMsg(msg_header, msg_payload) )
    {
        PALogError("can't report msg");
    }    
}

void reportAlarm(PA_ALARM *alarm)
{
	char msg_buf[MSG_BUFF_SIZE] = {0};
    MSGHEADER *msg_header = (MSGHEADER *)msg_buf;
    void* msg_payload = (void*)(msg_buf + sizeof(MSGHEADER));

    msg_header->srcID = MODULE_PA;
    msg_header->dstID = MODULE_INTF;
    msg_header->msgType = MSG_TYPE_COMMAND;
    msg_header->mType = get_mtype(msg_header->dstID);

    PCMDHEADER cmd = (PCMDHEADER)msg_payload;
    cmd->cmdType = CMD_EVENT;
    cmd->cmdCode = alarm->id;
    cmd->cmdIndex = 0;
    cmd->cmdLength = 0;

    msg_header->msgLength = sizeof(CMDHEADER);
    unsigned char *ptr = (unsigned char *)msg_payload;
    ptr += sizeof(CMDHEADER);

    int32_t tlvLength = 0;

    PARAM *tlv = (PARAM *)ptr;
    tlv->paraType = PARA_TYPE_PA_ADDR;
    tlv->paraLength = sizeof(uint8_t);
    tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);
   	*(ptr + sizeof(PARAM)+cmd->cmdLength) = alarm->pa_addr;
    cmd->cmdLength += tlvLength;

    msg_header->msgLength += cmd->cmdLength;
	PALogError("pa id %04x\n", alarm->pa_addr);
	msg_header->msgLength += sizeof(MSGHEADER);//

    if( RC_OK != CM_sendMsg(msg_header, msg_payload) )
    {
        PALogError("can't report msg");
    }
} 

void reportPaStatus(uint8_t pa_addr, lpa_status_t *lpa_status)
{
    char msg_buf[MSG_BUFF_SIZE] = {0};
    MSGHEADER *msg_header = (MSGHEADER *)msg_buf;
    void* msg_payload = (void*)(msg_buf + sizeof(MSGHEADER));

    msg_header->srcID = MODULE_PA;
    msg_header->dstID = MODULE_SYSTEM;
    msg_header->msgType = MSG_TYPE_COMMAND;

    PCMDHEADER cmd = (PCMDHEADER)msg_payload;
    cmd->cmdType = CMD_EVENT;
    cmd->cmdCode = CMD_EVT_PA_STATUS;
    cmd->cmdIndex = 0;
    cmd->cmdLength = 0;

    msg_header->msgLength = sizeof(CMDHEADER) + sizeof(MSGHEADER);
    
    uint8_t *ptr = (uint8_t *)msg_payload;
    ptr += sizeof(CMDHEADER);
    
    int32_t tlvLength = 0;

    PARAM *tlv = (PARAM *)ptr;
    tlv->paraType = PARA_TYPE_PA_ADDR;
    tlv->paraLength = sizeof(uint8_t);
    tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);
   	*(ptr + sizeof(PARAM)+cmd->cmdLength) = (pa_addr&0x0F);
    cmd->cmdLength += tlvLength;
	
	tlv = (PARAM *)(ptr + cmd->cmdLength);
    tlv->paraType = PARA_TYPE_PA_STATE;
    tlv->paraLength = sizeof(uint8_t);
    tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);
    *(ptr + sizeof(PARAM)+cmd->cmdLength) = (lpa_status->pa_switch & 0x1);
    cmd->cmdLength += tlvLength;
    
    tlv = (PARAM *)(ptr + cmd->cmdLength);
    tlv->paraType = PARA_TYPE_PA_TEMP;
    tlv->paraLength = sizeof(uint8_t);
    tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);
    *(ptr + sizeof(PARAM)+ cmd->cmdLength) = lpa_status->pa_temp;
    cmd->cmdLength += tlvLength;

    tlv = (PARAM *)(ptr + cmd->cmdLength);
    tlv->paraType = PARA_TYPE_UP_ATT;
    tlv->paraLength = sizeof(uint8_t);
    tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);
    *(ptr + sizeof(PARAM)+cmd->cmdLength) = lpa_status->pa_upatt;
    cmd->cmdLength += tlvLength;
       
    tlv = (PARAM *)(ptr + cmd->cmdLength);
    tlv->paraType = PARA_TYPE_DN_ATT;
    tlv->paraLength = sizeof(uint8_t);
    tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);
    *(ptr + sizeof(PARAM)+cmd->cmdLength) = lpa_status->pa_dnatt;
    cmd->cmdLength += tlvLength;

    tlv = (PARAM *)(ptr + cmd->cmdLength);
    tlv->paraType = PARA_TYPE_PA_DN_POWER;
    tlv->paraLength = sizeof(uint8_t);
    tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);
    *(ptr + sizeof(PARAM)+cmd->cmdLength) = lpa_status->pa_dn_power;
    cmd->cmdLength += tlvLength;

    tlv = (PARAM *)(ptr + cmd->cmdLength);
    tlv->paraType = PARA_TYPE_PA_DN_10_POWER;;
    tlv->paraLength = sizeof(uint8_t)*2;
    tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);
    *(int16_t *)tlv->paraValue = lpa_status->pa_dn_10_power;
    cmd->cmdLength += tlvLength;

   
    tlv = (PARAM *)(ptr + cmd->cmdLength);
    tlv->paraType = PARA_TYPE_PA_10_SWR;
    tlv->paraLength = sizeof(uint8_t);
    tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);
    *(ptr + sizeof(PARAM)+cmd->cmdLength) = lpa_status->pa_sw10ratio;
    cmd->cmdLength += tlvLength;
	
    tlv = (PARAM *)(ptr + cmd->cmdLength);
    tlv->paraType = PARA_TYPE_PA_TEMP_THRESHOLD;
    tlv->paraLength = sizeof(uint8_t);
    tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);
    *(ptr + sizeof(PARAM)+ cmd->cmdLength) = lpa_status->pa_tempthres;
    cmd->cmdLength += tlvLength;

    tlv = (PARAM *)(ptr + cmd->cmdLength);
    tlv->paraType = PARA_TYPE_PA_POWER_THRESHOLD;
    tlv->paraLength = sizeof(uint8_t);
    tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);
    *(ptr + sizeof(PARAM)+cmd->cmdLength) = lpa_status->pa_powerthres;
    cmd->cmdLength += tlvLength;
    msg_header->msgLength += cmd->cmdLength;

    if( RC_OK != CM_sendMsg(msg_header, msg_payload) )
    {
        PALogError("can't report msg");
    }
}

void paStatusHdlr(int8_t id, lpa_status_t paStatus)
{
    PA_ALARM alarm;
    alarm.pa_addr = id;
	int32_t tempwarn = get_pa_temp_warnthreshold();

	if (paStatus.pa_sw10ratio > 20)
    {
        if (paSwWarn[id] >= 5)
        {
            alarm.id = CMD_EVT_ALARM_PA_SWR;
            reportAlarm(&alarm);
            paSwWarn[id] = 0;
        }
        else
        {
            paSwWarn[id]++;
        }
    }
    else
    {
        paSwWarn[id] = 0;
    }

	if (paStatus.pa_temp >= tempwarn)
	{
		if (paTempWarn[id] >= 5)
		{
			alarm.id = CMD_EVT_ALARM_PA_OVER_TEMP;
			reportAlarm(&alarm);
			if(!is_pa_overtemp[id])
			{
				set_pa_switch(id+1, PA_SWITCH_OFF);
				is_pa_overtemp[id] = 1;				
				PALogWarning("pa[%d] temp is over ,close \n", id+1);
			}
			paTempWarn[id] = 0;
		}
		else
		{
			paTempWarn[id]++;
			//is_pa_overtemp[id] = 0;
		}
	}
	else
	{
		if(is_pa_overtemp[id])
		{
			set_pa_switch(id+1, PA_SWITCH_ON);
			is_pa_overtemp[id] = 0;
			PALogNotice("pa[%d] temp is down , open \n", id+1);
		}
		paTempWarn[id] = 0;
	}
    
}

void reportPaState(uint16_t dst_id, uint16_t cmd_code, uint16_t cmd_idx, uint8_t pa_addr, uint32_t entry, uint32_t type)
{	
    pa_ret_t ret = pa_ret_ok;
    char msg_buf[MSG_BUFF_SIZE] = {0};
    MSGHEADER *msg_header = (MSGHEADER *)msg_buf;
    void* msg_payload = (void*)(msg_buf + sizeof(MSGHEADER));

    msg_header->srcID = MODULE_PA;
    msg_header->dstID = dst_id;
    msg_header->msgType = MSG_TYPE_COMMAND;

    PCMDHEADER cmd = (PCMDHEADER)msg_payload;
    cmd->cmdType = CMD_GET_RESPONSE;
    cmd->cmdCode = cmd_code;
    cmd->cmdIndex = 0;
    cmd->cmdLength = 0;

    msg_header->msgLength = sizeof(CMDHEADER)+sizeof(MSGHEADER) ;
    
    uint8_t *ptr = (uint8_t *)msg_payload;
    ptr += sizeof(CMDHEADER);
    
    uint8_t value[2] = {0};
    ret = get_pa_status(pa_addr, entry, value);
    int32_t tlvLength = 0;
    int16_t val = value[0] | (value[1] & 0xffff) << 8;  
     
    if( pa_ret_ok != ret )
    {
        PALogError("can't get pa status");
        PARAM *tlv = (PARAM *)ptr;
        tlv->paraType = PARA_TYPE_RESULT;
        tlv->paraLength = sizeof(int32_t);
        *(ptr + sizeof(PARAM)) = PARA_VALUE_RESULT_FAILED;
        ptr += roundup8(sizeof(PARAM) + tlv->paraLength);
        cmd->cmdLength += roundup8(sizeof(PARAM) + tlv->paraLength);

        tlv = (PARAM *)ptr;
        tlv->paraType = PARA_TYPE_ERROR_CODE;
        tlv->paraLength = sizeof(uint32_t);
        *(uint32_t*)(ptr + sizeof(PARAM)) = PARA_VALUE_ERROR_PA_OK + ret;
        cmd->cmdLength += sizeof(uint32_t) * 3;
    }
    else
    {
        if(PA_STATUS_DN_10_POWER != entry)
        {
            PARAM *tlv = (PARAM *)ptr;
            tlv->paraType = PARA_TYPE_PA_ADDR;
            tlv->paraLength = sizeof(uint8_t);
            tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);
            *(ptr + sizeof(PARAM) + cmd->cmdLength) = pa_addr;
            cmd->cmdLength += tlvLength;

            tlv = (PARAM *)(ptr + cmd->cmdLength);
            tlv->paraType = type;
            tlv->paraLength = sizeof(uint8_t);
            tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);
            *(ptr + sizeof(PARAM) + cmd->cmdLength) = value[0];
            cmd->cmdLength += tlvLength;
        }
        else
        {
            PARAM *tlv = (PARAM *)ptr;
            tlv->paraType = PARA_TYPE_PA_ADDR;
            tlv->paraLength = sizeof(uint8_t);
            tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);
            *(ptr + sizeof(PARAM) + cmd->cmdLength) = pa_addr;
            cmd->cmdLength += tlvLength;

            tlv = (PARAM *)(ptr + cmd->cmdLength);
            tlv->paraType = type;
            tlv->paraLength = sizeof(uint8_t)*2;
            tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);
            *(int16_t *)tlv->paraValue = val; 
            cmd->cmdLength += tlvLength;
        }       

    }
   
    msg_header->msgLength += cmd->cmdLength;
    if( RC_OK != CM_sendMsg(msg_header, msg_payload) )
    {
        PALogError("can't report msg");
    }  
}

inline pa_ret_t tlv_parser_pa_addr(void* ptr, uint8_t *addr_code)
{
    pa_ret_t ret = pa_ret_ok;
    PARAM *tlv = (PARAM *)ptr;

    if( PARA_TYPE_PA_ADDR == tlv->paraType )
    {
        if( 1 == tlv->paraLength )
        {
            uint8_t pa_addr_code = *tlv->paraValue;

            *addr_code = pa_addr_code;

        }
        else
        {
            PALogError("recv wrong tlv, length=%u",tlv->paraLength);
            ret = pa_err_param;
        }
    }
    else
    {
        PALogError("recv wrong tlv, type=0x%x", tlv->paraType);
        ret = pa_err_param;
    }
    return ret;
}

void tlvPaMsgHdlr(PMSGHEADER header, void* payload)
{
	pa_ret_t ret = pa_ret_ok;
    uint32_t len = header->msgLength, cmd_len = 0;
    uint8_t *ptr = (uint8_t*)payload;
    uint16_t srcId = header->srcID;
    uint8_t pa_addr_code = 0;
    if( MODULE_PA != header->dstID )
    {
        PALogError("received a wrong tlv dst id = %d", header->dstID);
        return;
    }

    if( MSG_TYPE_COMMAND == header->msgType )
    {
        PCMDHEADER cmd = (PCMDHEADER)ptr;
        ptr += sizeof(CMDHEADER);
        len -= sizeof(CMDHEADER);

        cmd_len = cmd->cmdLength;

        if( CMD_SET == cmd->cmdType )
        {
            switch( cmd->cmdCode ) 
            {
               case CMD_CODE_SET_VAILD_PA:
                  {
                     if( cmd_len >= sizeof(PARAM) )
                     {
                         ret =  initPaCom(ptr);
                     }
                  }

                  break;

                case CMD_CODE_PA_SWITCH_OFF:
                  {
                      if( cmd_len >= sizeof(PARAM) )
                      {
                          ret = tlv_parser_pa_addr(ptr, &pa_addr_code);                      
                          if( pa_ret_ok == ret )
                          {
                              ret = set_pa_switch(pa_addr_code, PA_SWITCH_OFF);
                          }
                      }
                      else
                      {
                          for (int i = 0; i < PA_NUM; i++)
                          {
                              ret = set_pa_switch(i, PA_SWITCH_OFF);

                              if( pa_not_found == ret )
                              {
                                  PALogError("pa[%d] not found", i);
                              }
                          } 

                          ret = pa_ret_ok;
                      }
                }
                break;

            case CMD_CODE_PA_SWITCH_ON:
                {
                    if( cmd_len >= sizeof(PARAM) )
                    {
                        ret = tlv_parser_pa_addr(ptr, &pa_addr_code);
                        if( pa_ret_ok == ret )
                        {
                            ret = set_pa_switch(pa_addr_code, PA_SWITCH_ON);
                        }
                    }
                    else
                    {
                        for(int i = 0; i < PA_NUM; i++)
                        {
                            ret = set_pa_switch(i, PA_SWITCH_ON);
                            if( pa_not_found == ret )
                            {
                                printf("pa[%d] not found \n", i);
                                ret = pa_ret_ok;
                            }
                        }

                        ret = pa_ret_ok;
                    }
                }
                break;

			case CMD_CODE_PA_RESET:
                {
                    if( cmd_len >= sizeof(PARAM) )
                    {
                        ret = tlv_parser_pa_addr(ptr, &pa_addr_code);
                        if( pa_ret_ok == ret )
                        {
                            ret = set_pa_reset(pa_addr_code);
                        }
                    }
                    else
                    {
                        for(int i = 0; i < PA_NUM; i++)
                        {
                            ret = set_pa_reset(i);
                            if( pa_not_found == ret )
                            {
                                printf("pa[%d] not found \n", i);
                                ret = pa_ret_ok;
                            }
                        }
                    }
                }
                break;

			case CMD_CODE_UP_ATT:
                {
                    uint8_t up_att = 0;
                    uint32_t tlvRecvFlag = 0;

                    while( (cmd_len >= sizeof(PARAM)) && (pa_ret_ok == ret) )
                    {
                        PARAM *tlv = (PARAM *)ptr;
                        int32_t tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);
                        
                        switch( tlv->paraType ) {
                            case PARA_TYPE_PA_ADDR:
                                ret = tlv_parser_pa_addr(ptr, &pa_addr_code);
                                if( pa_ret_ok != ret )
                                {
                                    break;
                                }

                                ptr += tlvLength;
                                cmd_len -= tlvLength;
                                tlvRecvFlag |= 1;
                                break;

                            case PARA_TYPE_UP_ATT:

                        	     if( tlv->paraLength == 1)
                                {
                                    uint8_t power = tlv->paraValue[0];
					                up_att = power;
#if 0                                    
                                    if( power > 40 )
                                    {
                                        power = 40;
                                    }
                                    else if( power < 9 )
                                    {
                                        power = 9;
                                    }

                                    
                                    up_att = 40 - power;
#endif                                    
                                }
                                else
                                {
                                    PALogError("recv wrong tlv, length=%u", tlv->paraLength);
                                    ret = pa_err_param;
                                    break;
                                }

                                ptr += tlvLength;
                                cmd_len -= tlvLength;
                                tlvRecvFlag |= 2;
                                break;
                            default:
                                PALogError("tlv type %d not supported", tlv->paraType);
                                ret = pa_not_supported;
                                break;
                        }
                    }
                    if( pa_ret_ok == ret )
                    {
                        if( tlvRecvFlag == 0x3 )
                        {

#ifdef KEEP_PA_ON_FOR_TEST
                            ret = set_up_att(pa_addr_code, up_att);
#else                            
                            if( PARA_VALUE_GSM_WILELESS_ON == is_gsm_ready )
                            {
                                ret = set_up_att(pa_addr_code, up_att);
                            }
#endif
                            pa_up_att[pa_addr_code] = up_att;
                            PALogInfo("pa_up_att:%d", pa_up_att[pa_addr_code]);
                        }
                        else
                        {
                            PALogError("tlv missing detected");
                            ret = pa_err_param;
                        }
                    }
                }
                break;

			case CMD_CODE_DN_ATT:
                {
                    uint8_t dn_att = 0;
                    uint32_t tlvRecvFlag = 0;

                    while( (cmd_len >= sizeof(PARAM)) && (pa_ret_ok == ret) )
					{

                        PARAM *tlv = (PARAM *)ptr;
                        int32_t tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);

                        switch( tlv->paraType ) {

                            case PARA_TYPE_PA_ADDR:
                            	ret = tlv_parser_pa_addr(ptr, &pa_addr_code);
                                if( pa_ret_ok != ret )
                                {
                                    break;
                                }
                                ptr += tlvLength;
                                cmd_len -= tlvLength;
                                tlvRecvFlag |= 1;
                                break;

                            case PARA_TYPE_DN_ATT:
                                if( tlv->paraLength == 1)
                                {
                                    uint8_t power = tlv->paraValue[0];
					                dn_att = power;
#if 0
                                    if( power > 60 )
                                    {
                                        power = 60;
                                    }
                                    else if( power < 1 )
                                    {
                                        power = 1;
                                    }
                                    dn_att = 40 - power;

                                    power = tlv->paraValue[1];
                                    if( power > 40 )
                                    {
                                        power = 40;
                                    }
                                    else if( power < 9 )
                                    {
                                        power = 9;
                                    }
                                    up_att = 40 - power;
#endif
				                }
                                else
                                {

                                    PALogError("recv wrong tlv, length=%u", tlv->paraLength);
                                    ret = pa_err_param;
                                    break;
                                }

                                ptr += tlvLength;
                                cmd_len -= tlvLength;
                                tlvRecvFlag |= 2;
                                break;
                            default:
                                PALogError("tlv type %d not supported", tlv->paraType);
                                ret = pa_not_supported;
                                break;
                        }
					}
                    if( pa_ret_ok == ret )
                    {
                        if( tlvRecvFlag == 0x3 )
                        {
#ifdef KEEP_PA_ON_FOR_TEST
                            ret = set_dn_att(pa_addr_code, dn_att);
#else
                            if( PARA_VALUE_GSM_WILELESS_ON == is_gsm_ready )
							{
                                ret = set_dn_att(pa_addr_code, dn_att);
                            }
#endif
                            pa_dn_att[pa_addr_code] = dn_att;
                        }
                        else
                        {
                            PALogError("tlv missing detected");
                            ret = pa_err_param;

                        }
                    }
                }
                break;

			case CMD_CODE_TEMP_THRESHOLD:
				{
					uint8_t pa_addrcode = 0;
					uint8_t temp_threshold = 0;
					uint32_t tlvRecvFlag = 0;

					while( (cmd_len >= sizeof(PARAM)) && (pa_ret_ok == ret) )
					{
						PARAM *tlv = (PARAM *)ptr;
						int32_t tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);
						
						switch( tlv->paraType ) {
							case PARA_TYPE_PA_ADDR:
								ret = tlv_parser_pa_addr(ptr, &pa_addrcode);
								if( pa_ret_ok != ret )
								{
									break;
								}

								ptr += tlvLength;
								cmd_len -= tlvLength;
								tlvRecvFlag |= 1;
								break;

							case PARA_TYPE_PA_TEMP_THRESHOLD:

								 if( tlv->paraLength == 1)
								{
									uint8_t temp = tlv->paraValue[0];
									temp_threshold = temp;
								  
								}
								else
								{
									PALogError("recv wrong tlv, length=%u", tlv->paraLength);
									ret = pa_err_param;
									break;
								}

								ptr += tlvLength;
								cmd_len -= tlvLength;
								tlvRecvFlag |= 2;
								break;
							default:
								PALogError("tlv type %d not supported", tlv->paraType);
								ret = pa_not_supported;
								break;
						}
					}
					if( pa_ret_ok == ret )
					{
						if( tlvRecvFlag == 0x3 )
						{
							ret = set_temp_threshold(pa_addrcode, temp_threshold);
							pa_temp_threshold[pa_addrcode] = temp_threshold;
							PALogInfo("pa_temp_threshold:%d", pa_temp_threshold[pa_addrcode]);
						}
						else
						{
							PALogError("tlv missing detected");
							ret = pa_err_param;
						}
					}
				}
				break;

			case CMD_CODE_POWER_THRESHOLD:
				{
					uint8_t pa_addrcode = 0;
					uint8_t power_threshold = 0;
					uint32_t tlvRecvFlag = 0;

					while( (cmd_len >= sizeof(PARAM)) && (pa_ret_ok == ret) )
					{

						PARAM *tlv = (PARAM *)ptr;
						int32_t tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);

						switch( tlv->paraType ) {

							case PARA_TYPE_PA_ADDR:
								ret = tlv_parser_pa_addr(ptr, &pa_addrcode);
								if( pa_ret_ok != ret )
								{
									break;
								}
								ptr += tlvLength;
								cmd_len -= tlvLength;
								tlvRecvFlag |= 1;
								break;

							case PARA_TYPE_PA_POWER_THRESHOLD:
								if( tlv->paraLength == 1)
								{
									uint8_t power = tlv->paraValue[0];
									power_threshold = power;
								}

								else
								{

									PALogError("recv wrong tlv, length=%u", tlv->paraLength);
									ret = pa_err_param;
									break;
								}

								ptr += tlvLength;
								cmd_len -= tlvLength;
								tlvRecvFlag |= 2;
								break;
							default:
								PALogError("tlv type %d not supported", tlv->paraType);
								ret = pa_not_supported;
								break;
						}
					}
					if( pa_ret_ok == ret )
					{
						if( tlvRecvFlag == 0x3 )
						{
							ret = set_power_threshold(pa_addrcode, power_threshold);
							pa_power_threshold[pa_addrcode] = power_threshold;
							PALogInfo("pa_power_threshold:%d", pa_power_threshold[pa_addrcode]);
						}
						else
						{
							PALogError("tlv missing detected");
							ret = pa_err_param;

						}
					}
				}
				break;

//here is test heartbeat
#ifdef MODULE_TEST
        case CMD_CODE_SYSMONITOR_TEST_MODULE:
            PALogError("----- test module pa ----- %04x", CMD_CODE_SYSMONITOR_TEST_MODULE);
            while(1)
            {

            }
            break;
#endif     
            default:
                PALogError("msg cmd %d not supported", cmd->cmdCode);
                ret = pa_not_supported;
                break;
            }

            if( pa_ret_ok == ret )
            {
                reportCmdResult(srcId, cmd->cmdCode, cmd->cmdIndex,
                    PARA_VALUE_RESULT_SUCCESS, PARA_VALUE_ERROR_NO_ERROR, pa_addr_code);
            }
            else
            {
                reportCmdResult(srcId, cmd->cmdCode, cmd->cmdIndex,
                    PARA_VALUE_RESULT_FAILED, ret, pa_addr_code);
            }
        }

        else if( CMD_GET == cmd->cmdType )
        {
			switch( cmd->cmdCode ) {
				case CMD_CODE_GET_PA_SWITCH:
                {
                    if( cmd_len >= sizeof(PARAM) )
                    {
                        
                        ret = tlv_parser_pa_addr(ptr, &pa_addr_code);
                        if( pa_ret_ok == ret )
                        {
                            reportPaState(srcId, CMD_CODE_GET_PA_SWITCH, cmd->cmdIndex, pa_addr_code, PA_STATUS_SWITCH, PARA_TYPE_PA_SWITCH);
                        }
                    }
                    else
                    {
                        ret = pa_err_param;
                    }
                }
                break;

				case CMD_CODE_GET_PA_STATE:
                {
                    if( cmd_len >= sizeof(PARAM) )
                    {
                        ret = tlv_parser_pa_addr(ptr, &pa_addr_code);
                        if( pa_ret_ok == ret )
                        {
                            reportPaState(srcId, CMD_CODE_GET_PA_STATE, cmd->cmdIndex, pa_addr_code, PA_STATUS_STATE, PARA_TYPE_PA_STATE);
                        }
                    }
                    else
                    {
                        ret = pa_err_param;
                    }
                }
                break;

            	case CMD_CODE_GET_PA_TEMP:
                {
                    if( cmd_len >= sizeof(PARAM) )
                    {
                        ret = tlv_parser_pa_addr(ptr, &pa_addr_code);
                        if( pa_ret_ok == ret )
                        {
                            reportPaState(srcId, CMD_CODE_GET_PA_TEMP, cmd->cmdIndex, pa_addr_code, PA_STATUS_TEMP, PARA_TYPE_PA_TEMP);
                        }
                    }
                    else
                    {
                        ret = pa_err_param;
                    }
                }
                break;

            	case CMD_CODE_GET_PA_UP_ATT:
                {
                    if( cmd_len >= sizeof(PARAM) )
                    {
                        ret = tlv_parser_pa_addr(ptr, &pa_addr_code);
                        if( pa_ret_ok == ret )
                        {
                            reportPaState(srcId, CMD_CODE_GET_PA_UP_ATT, cmd->cmdIndex, pa_addr_code, PA_STATUS_UP_ATT, PARA_TYPE_UP_ATT);
                        }
                    }
                    else
                    {
                        ret = pa_err_param;
                    }
                }
                break;

            	case CMD_CODE_GET_PA_DN_ATT:
                {
                    if( cmd_len >= sizeof(PARAM) )
                    {
                        ret = tlv_parser_pa_addr(ptr, &pa_addr_code);
                        if( pa_ret_ok == ret )
                        {
                            reportPaState(srcId, CMD_CODE_GET_PA_DN_ATT, cmd->cmdIndex, pa_addr_code, PA_STATUS_DN_ATT, PARA_TYPE_DN_ATT);
                        }
                    }
                    else
                    {
                        ret = pa_err_param;
                    }
                }
                break;
            
            	case CMD_CODE_GET_PA_DN_POWER:
                {
                    if( cmd_len >= sizeof(PARAM) )
                    {
                        ret = tlv_parser_pa_addr(ptr, &pa_addr_code);
                        if( pa_ret_ok == ret )
                        {
                            reportPaState(srcId, CMD_CODE_GET_PA_DN_POWER, cmd->cmdIndex, pa_addr_code, PA_STATUS_DN_POWER, PARA_TYPE_PA_DN_POWER);
                        }
                    }
                    else
                    {
                        ret = pa_err_param;
                    }
                }
                break;

            	case CMD_CODE_GET_PA_DN_10_POWER:
                {
                    if( cmd_len >= sizeof(PARAM) )
                    {
                        ret = tlv_parser_pa_addr(ptr, &pa_addr_code);
                        if( pa_ret_ok == ret )
                        {
                            reportPaState(srcId, CMD_CODE_GET_PA_DN_10_POWER, cmd->cmdIndex, 
												pa_addr_code, PA_STATUS_DN_10_POWER, PARA_TYPE_PA_DN_10_POWER);

                        }
                    }
                    else
                    {
                        ret = pa_err_param;
                    }
                }
                break;
           
            	case CMD_CODE_GET_PA_10_SWR:
                {
                    if( cmd_len >= sizeof(PARAM) )
                    {
                        ret = tlv_parser_pa_addr(ptr, &pa_addr_code);
                        if( pa_ret_ok == ret )
                        {
                            reportPaState(srcId, CMD_CODE_GET_PA_10_SWR, cmd->cmdIndex, pa_addr_code, PA_STATUS_SW10RADIO, PARA_TYPE_PA_10_SWR);
                        }
                    }
                    else
                    {
                        ret = pa_err_param;
                    }
                }
                break;
				
				case CMD_CODE_GET_TEMP_THRESHOLD:
                {
                    if( cmd_len >= sizeof(PARAM) )
                    {
                        //uint8_t pa_addr_code = 0;
                        ret = tlv_parser_pa_addr(ptr, &pa_addr_code);
                        if( pa_ret_ok == ret )
                        {
                            reportPaState(srcId, CMD_CODE_GET_TEMP_THRESHOLD, cmd->cmdIndex, pa_addr_code, PA_STATUS_TEMPTHRES, PARA_TYPE_PA_TEMP_THRESHOLD);

                        }
                    }
                    else
                    {
                        ret = pa_err_param;
                    }
                }
                break;

			    case CMD_CODE_GET_POWER_THRESHOLD:
                {
                    if( cmd_len >= sizeof(PARAM) )
                    {
                        //uint8_t pa_addr_code = 0;
                        ret = tlv_parser_pa_addr(ptr, &pa_addr_code);
                        if( pa_ret_ok == ret )
                        {
                            reportPaState(srcId, CMD_CODE_GET_POWER_THRESHOLD, cmd->cmdIndex, pa_addr_code, PA_STATUS_POWERTHRES, PARA_TYPE_PA_POWER_THRESHOLD);
                        }
                    }
                    else
                    {
                        ret = pa_err_param;
                    }
                }
                break;
				
  			default:
                PALogError("msg cmd %d not supported", cmd->cmdCode);
                break;
            }
            
            if( pa_ret_ok != ret )
            {
                reportCmdResult(srcId, cmd->cmdCode, cmd->cmdIndex, PARA_VALUE_RESULT_FAILED, ret, pa_addr_code);
            }
        }

        else if( CMD_EVENT == cmd->cmdType )
        {
            switch( cmd->cmdCode ) {
         		case CMD_CODE_SYS_REBOOT:
#if 0
                {
                    
                    if( pa_ret_ok == ret )
                    {
                    	ret = set_up_att(0, 30);
                        if( pa_ret_ok == ret )
                        {
                            ret = set_dn_att(1, 30);
                            if( pa_not_found == ret )
                            {
                                ret = pa_ret_ok;
                            }
                        }
                    }
                }
#endif
                break;  
		
            case CMD_CODE_SYS_SLEEP:
#if 0
                {
                    ret = set_pa_switch(0, PA_SWITCH_OFF);
                    if( pa_ret_ok == ret )
                    {
                        ret = set_pa_switch(1, PA_SWITCH_OFF);
                        if( pa_not_found == ret )
                        {
                            ret = pa_ret_ok;
                        }
                    }
                }
#endif
                break;
            case CMD_CODE_SYS_WAKE:
#if 0
                {
                    ret = set_pa_switch(0, PA_SWITCH_ON);
                    if( pa_ret_ok == ret )
                    {
                        ret = set_pa_switch(1, PA_SWITCH_ON);
                        if( pa_not_found == ret )
                        {
                            ret = pa_ret_ok;
                        }
                    }
                }
#endif 
                break;
            case CMD_GSM_EVT_STATUS:
#if 0
                {
                    if( cmd_len >= sizeof(PARAM) )
                    {
                        PARAM *tlv = (PARAM *)ptr;

                        if( PARA_TYPE_GSM_WILELESS_STATE == tlv->paraType )
                        {
                            if( 4 == tlv->paraLength )
                            {
#ifdef KEEP_PA_ON_FOR_TEST
                                is_gsm_ready = PARA_VALUE_GSM_WILELESS_ON;
#else
                                is_gsm_ready = *(uint32_t*)(ptr + sizeof(PARAM));
#endif
                                if( PARA_VALUE_GSM_WILELESS_ON == is_gsm_ready )
                                {

                                    ret = set_up_att(0, pa_up_att[0]);
                                    if( pa_ret_ok == ret )
                                    {

                                        ret = set_dn_att(1, pa_dn_att[1]);
                                        if( pa_not_found == ret )
                                        {
                                            ret = pa_ret_ok;
                                        }
                                    }
                                }
                                else
                                {

                                    ret = set_up_att(0, 30);
                                    if( pa_ret_ok == ret )
                                    {

                                        ret = set_dn_att(0, 30);
                                        if( pa_not_found == ret )
                                        {
                                            ret = pa_ret_ok;
                                        }
                                    }
                                }
                            }
                            else
                            {
                                ret = pa_err_param;
                            }
                        }
                        else
                        {
                            ret = pa_not_supported;
                        }
                    }
                    else
                    {
                        ret = pa_err_param;
                    }
                }
#endif
                break;
            default:
                PALogError("msg cmd %d not supported", cmd->cmdCode);
                break;
            }
        }
        else
        {
            PALogError("cmd type %d not supported", cmd->cmdType);
        }
    }

	else if( MSG_TYPE_INTERNAL == header->msgType )
    {

    }
    else
    {
        PALogError("msg type %d not supported", header->msgType);
    }
}

static void* patask_main(void *arg __attribute__((unused)))
{
    pthread_setname_np(pthread_self(), "patask");

  //  if( pa_ret_ok != initPaCom() )
//    {
   //     printf("Can't initialize PA communication \n");
//        pthread_exit((void*)0);
 //   }

    char msg_buf[MSG_BUFF_SIZE] = {0};
    MSGHEADER *msg_header = (MSGHEADER *)msg_buf;
    void* msg_payload = (void*)(msg_buf + sizeof(MSGHEADER));
    uint8_t pa_polling = 0;
    uint8_t paHeartBeat = 0;
    while( ! stop_process )
    {
        /* get msg from system process */
        if( RC_OK == MSG_read_nonblock(MODULE_PA, msg_header, msg_payload) )
        {
            tlvPaMsgHdlr(msg_header, msg_payload);
        }

        /* PA status polling */
        if( pa_polling >= 180 )
        {
            pa_polling = 0;

            pa_status status = pa_status_polling();

            for(int i = 0; i < PA_NUM; i++)
            {
                if(status.pa_present[i])
                {
                    if( status.pa_state[i])
                    {
                         paStatusHdlr(i, status.pa_status[i]);
                    }
                    
                    reportPaStatus(status.pa_addr[i], &status.pa_status[i]);
                }
            }
        }
        else
        {
            pa_polling++;
            
        }
        sleep(1);
        paHeartBeat++;
        if ( paHeartBeat >= 5 )
        {
            reportPaHeartBeat();
            paHeartBeat = 0;
        }
    }
    
    termPaCom();
    PALogError("patask thread exit");
    pthread_exit((void*)0);
}

RESULT patask_init()
{
    pthread_t thread;

    if( RC_OK != MOD_register(&modPaInfo) )
    {
        PALogError("Can't register module with syscore");
        return RC_FAIL;
    }

    pthread_create(&thread, NULL, patask_main, 0);

    return RC_OK;
}

#if 0
int main()
{
    void *arg = NULL;

    if( RC_OK != MOD_register(&modPaInfo) )
    {
        printf("Can't register module with syscore\n");
        return -1;
    }:w


    patask_main(arg);

    return 0;
}
#endif

